local love = require "love"
local Bullet = require "Object/Bullet"
local Ship = require "Object/Ship"
local Asteroid = require "Object/Asteroid"
local Button = require "Object/Button"
local Music = require "Object/Music"

local ship = Ship:new()
local bullets = {}
local asteroids = {}
local timer = 0
local musics = {}

local WIDTH

local game = {
    state = {
        menu = true,
        running = false,
        ended = false
    },
    points = 0
}

local buttons = {
    menu_state = {}
}

local mouse = {}

local function change_game_state(state)
    game.state.menu = (state == "menu")
    game.state.running = (state == "running")
    game.state.ended = (state == "ended")
end

local function start_new_game()
    change_game_state("running")
    game.points = 0

    timer = 0
    bullets = {}
    asteroids = {}
    ship = Ship:new()
end

function love.mousepressed(x, y, _button, _istouch, _presses)
    if game.state.menu then
        if _button == 1 then     -- left click
            for index in pairs(buttons.menu_state) do
                buttons.menu_state[index]:click(x, y)
            end
        end
    end
end

-- to prevent continuous bullet firing 
-- and make it so that pressing the spacebar only fires one bullet per press
function love.keyreleased(key)
    if key == SHIP_ATTACK then
        local bullet = Bullet:new{
            x = ship.x + ship.radius * math.cos(ship.view_angle),
            y = ship.y - ship.radius * math.sin(ship.view_angle),
            angle = ship.view_angle,
            survive = true
        }
        if bullet.survive then table.insert(bullets, 1, bullet) end

        musics.attack:play(false, true)
    end
end

function love.load()
    math.randomseed(os.time())

    love.mouse.setVisible(false)    -- hide the mouse

    WIDTH = love.graphics.getWidth()
    HEIGHT = love.graphics.getHeight()

    table.insert(asteroids, 1, Asteroid:new(ship.view_angle))

    buttons.menu_state.play_game = Button:new(10, 20, "Play Game", start_new_game, nil, 110, 30)
    -- buttons.menu_state.settings  = Button:new(10, 70, "Settings", nil, nil, 100, 30)
    buttons.menu_state.exit_game = Button:new(10, 70, "Exit Game", love.event.quit, nil, 110, 30)

    musics.attack = Music:new("resource/music/shoot_sound.mp3", "static", 0.1)
    musics.bgm = Music:new("resource/music/bgm.mp3", "stream", 0.6)
    musics.thrust = Music:new("resource/music/thrusting_sound.mp3", "static", 0.2)
    musics.asteroid_damage = Music:new("resource/music/asteroid_damage_sound.mp3", "static")
    musics.dead = Music:new("resource/music/ship_dead_sound.mp3", "static", 1)

    musics.bgm:play(true)
end

function love.update(dt)
    if game.state.menu then
        mouse.x, mouse.y = love.mouse.getPosition()
    elseif game.state.running then
        -- add a asteroid  
        timer = timer + dt
        if timer >= 4 then
            table.insert(asteroids, 1, Asteroid:new(ship.view_angle))
            timer = 0
        end

        -- collide and damage
        for i = #asteroids, 1, -1 do
            -- asteroid and bullet
            -- using reverse iteration to remove elements 
            -- helps avoid altering the array's order when elements are deleted
            for j = #bullets, 1, -1 do
                if bullets[j]:collide(asteroids[i]) then
                    asteroids[i]:damage(bullets[j].x, bullets[j].y)
                    table.remove(bullets, j)
                end
            end

            -- asteroid and ship
            if asteroids[i]:collide(ship.x, ship.y, ship.radius) then
                ship.survive = false
                musics.dead:play(false)
                love.timer.sleep(3)
            end

            if asteroids[i].survive == 0 then
                game.points = game.points + 5
                table.remove(asteroids, i)
                musics.asteroid_damage:play(false, true)
            else
                asteroids[i]:move()
            end
        end

        if ship.survive then
            ship:move()
        else
            change_game_state("menu")
            return
        end

        for i = #bullets, 1, -1 do
            if  bullets[i].survive then
                bullets[i]:move()
            else
                table.remove(bullets, i)
            end
        end

        -- music
        if ship.thrust then
            musics.thrust:play(false, true)
        end

    end
end

function love.draw()
    if game.state.running then
        love.graphics.setColor(0, 1, 0)
        love.graphics.printf("FPS: " .. love.timer.getFPS(), 10, 10, WIDTH)
        love.graphics.printf("Velocity: " .. math.floor(ship.velocity), 10, 30, WIDTH)

        love.graphics.setColor(1, 0, 0)
        love.graphics.printf("Points: " .. game.points, love.graphics.newFont(24), 0, 10, love.graphics.getWidth(), "center")

        ship:draw()
        for i = 1, #bullets do bullets[i]:draw() end
        for i = 1, #asteroids do asteroids[i]:draw() end
    elseif game.state.menu then
        buttons.menu_state.play_game:draw()
        -- buttons.menu_state.settings:draw()
        buttons.menu_state.exit_game:draw()

        love.graphics.setColor(1, 1, 0)
        love.graphics.circle("fill", mouse.x, mouse.y, 10)
    end
end
